package com.sztz.service;

import cn.hutool.core.codec.Base64;
import cn.hutool.core.exceptions.ExceptionUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.ReflectUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.excel.EasyExcelFactory;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.support.ExcelTypeEnum;
import com.alibaba.excel.write.merge.OnceAbsoluteMergeStrategy;
import com.alibaba.excel.write.metadata.WriteSheet;
import com.alibaba.excel.write.metadata.WriteTable;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.sztz.constants.CommonConstants;
import com.sztz.dao.UserDao;
import com.sztz.entity.User;
import com.sztz.excel.ExcelVoListener;
import com.sztz.handle.UserHandler;
import com.sztz.result.ResultEnum;
import com.sztz.result.ServiceException;
import com.sztz.utils.CommUtils;
import com.sztz.utils.DbLoadDataUtils;
import com.sztz.utils.EasyExcelUtils;
import com.sztz.vo.UserExcelVo;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.sql.DataSource;
import java.io.*;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.Executor;
import java.util.function.Consumer;
import java.util.stream.Collectors;
import java.util.stream.Stream;


/**
 * User用户信息服务层
 * @author yzy
 * @date 2022/7/5 15:07
 */
@Service
@Slf4j
@RequiredArgsConstructor
public class UserTestService extends ServiceImpl<UserDao,User> {
    private final UserDao userDao;
    private final DataSource dataSource;
    @Qualifier("yzyExecutor")
    private final Executor yzyExecutor;


    /**
     * 用户信息导出
     * @author yzy
     * @date 2022/08/01 15:53
     */
    public String downloadExcel(){
        //先生成临时文件
        File tempFile= CommUtils.createTempFile("UserList", ExcelTypeEnum.XLSX.getValue());
        try(BufferedOutputStream outputStream = FileUtil.getOutputStream(tempFile)){
            //Excel写临时文件
            ExcelWriter excelWriter = EasyExcelUtils.getExcelWriter(outputStream, UserExcelVo.class);
            WriteSheet writeSheet = EasyExcelUtils.getWriteSheet("用户信息",0);
            //流式查询处理
            UserHandler userHandler = new UserHandler(excelWriter, writeSheet);
            userDao.queryAllUser(userHandler);
            userHandler.lastRowHandle();
            excelWriter.finish();
            return Base64.encode(tempFile);
        } catch (IOException e) {
            log.error(ExceptionUtil.stacktraceToString(e));
            return StrUtil.EMPTY;
        } finally {
            FileUtil.del(tempFile);
        }
    }

    /**
     * 用户信息导出，第一行是标题，第二行是head头
     * @author yzy
     * @date 2022/09/01 18:31
     */
    public String downLoadTableExcel(){
        //先生成临时文件
        File tempFile= CommUtils.createTempFile("UserList", ExcelTypeEnum.XLSX.getValue());
        try(BufferedOutputStream outputStream = FileUtil.getOutputStream(tempFile)){
            //定义第一行标题合并单元格
            OnceAbsoluteMergeStrategy onceAbsoluteMergeStrategy = new OnceAbsoluteMergeStrategy(0, 0, 0, 5);
            //Excel写入器
            ExcelWriter excelWriter = EasyExcelUtils.getExcelWriter(outputStream, onceAbsoluteMergeStrategy);
            WriteSheet writeSheet = EasyExcelUtils.getWriteSheet("用户信息",0);
            //先写第一行的标题
            writeExcelTitle(excelWriter,writeSheet);
            //流式查询处理，再从第二行开始写head头与数据
            UserHandler userHandler = new UserHandler(excelWriter, writeSheet);
            userDao.queryAllUser(userHandler);
            userHandler.lastRowHandle();

            excelWriter.finish();
            //将临时文件生成Base64返回
            return Base64.encode(tempFile);
        } catch (IOException e) {
            log.error(ExceptionUtil.stacktraceToString(e));
            return StrUtil.EMPTY;
        } finally {
            FileUtil.del(tempFile);
        }
    }
    /**
     * 先用table的方式写第一行的标题
     * @author yzy
     * @date 2022/09/01 18:31
     */
    private void writeExcelTitle(ExcelWriter excelWriter, WriteSheet writeSheet) {
        WriteTable writeTable0 = EasyExcelFactory.writerTable(0).needHead(Boolean.FALSE).build();
        List<List<String>> tableData = new ArrayList<>();
        tableData.add(Arrays.asList(StrUtil.format("用户统计表{}-{}","2022-08-01","2022-09-01")));
        excelWriter.write(tableData,writeSheet,writeTable0);
    }
    /**
     * 查询所有用户信息
     * @author yzy
     * @date 2022/08/03 13:44
     */
    public List<User> queryList(){
        return userDao.selectList(new QueryWrapper<User>());
    }

    /**
     * excel导入用户信息
     * @inputStream 输入流
     * @author yzy
     * @date 2022/08/01 15:53
     */
    @Transactional(rollbackFor = Exception.class)
    public void importUserFromExcel(String filePath){
        log.info("importUserFromExcel ,filePath={}",filePath);
        File file = FileUtil.file(filePath);
        try(BufferedInputStream inputStream = FileUtil.getInputStream(file)){
            Consumer<List<UserExcelVo>> userConsumer = data->{
                //UserExcelVo对象转成User实体对象
                List<User> collect = data.stream().map(UserExcelVo::convertToUser).collect(Collectors.toList());
                //批量插入数据库
                userDao.batchInsertUser(collect,"T_USER");
            };
            EasyExcelFactory.read(inputStream, UserExcelVo.class, new ExcelVoListener<>(userConsumer)).sheet().doRead();
        }catch (Exception e){
            log.error(ExceptionUtil.stacktraceToString(e));
            throw new ServiceException(ResultEnum.UNKNOWN_ERROR);
        }
    }

    /**
     * loadDataLocalInFile方式批量导入用户信息到Mysql
     * @param inputStream 数据流
     * @return int 总处理行数
     * @author yzy
     * @date 2022/08/03 15:30
     */
    public int loadDataInFileForUser(InputStream inputStream){
        Field[] fields = ReflectUtil.getFields(User.class);
        List<String> collect = Stream.of(fields).map(Field::getName).filter(name->!StrUtil.equalsAnyIgnoreCase(name,"id","createTime")).map(StrUtil::toUnderlineCase).collect(Collectors.toList());
        String tableName="T_USER";
        String loadDataSql= DbLoadDataUtils.createSql(CommonConstants.MY_DB_NAME,tableName,collect.stream().collect(Collectors.joining(StrUtil.COMMA)));
        log.info(loadDataSql);
        return DbLoadDataUtils.dbLoadDataFromInputStream(dataSource, loadDataSql, inputStream);
    }

    @Async("yzyExecutor")
    public void batchInsertUser() throws InterruptedException {
        testTrace2();
        Thread.sleep(2000);
        log.info("正在执行插入");
    }

    public void testTrace(){
        log.info("这是testTrace");
        testTrace3();
    }
    public void testTrace2(){
        log.info("testTrace2");
    }
    public void testTrace3(){
        log.info("testTrace3");
        yzyExecutor.execute(()->testTrace4());
    }
    public void testTrace4(){
        log.info("testTrace4");
    }

    public User getUserById(Integer id) {
        return userDao.getUserById(id);
    }
    public int updateUser(User user){
        return userDao.updateUser(user);
    }
}
